#ifndef __SHAREDPOINTER_H
#define __SHAREDPOINTER_H

#include <cstddef>

template<typename A>
class SharedPointer
{
	struct Base
	{
		virtual ~Base() {}
		Base(A *a_raw) :m_raw(a_raw), m_count(1) {}
		A *m_raw;
		size_t m_count;
	};

	template<typename B>
	struct Derived: Base
	{
		virtual ~Derived() {delete static_cast<B *>(m_raw); }
		Derived(B *a_raw) :Base(a_raw) {}
	};

public:
	SharedPointer()
		:m_aux(0)
	{}

	template<typename C>
	explicit SharedPointer(C *a_raw)
		:m_aux(a_raw == 0? 0: new Derived<C >(a_raw))
	{}

	SharedPointer(const SharedPointer &a_another)
		:m_aux(a_another.m_aux)
	{
		if (m_aux != 0)
			++m_aux->m_count;
	}

	SharedPointer &operator =(const SharedPointer &a_another)
	{
		SharedPointer l_another(a_another);
		swap(l_another);
		return *this;
	}

	~SharedPointer()
	{
		if (m_aux != 0 && --m_aux->m_count == 0)
			delete m_aux;
	}

	template<typename D>
	void reset(D *a_raw)
	{
		SharedPointer l_another(a_raw);
		swap(l_another);
	}

	A *get() const
	{
		return m_aux == 0? 0: m_aux->m_raw;
	}

	A &operator *() const
	{
		return *get();
	}

	A *operator ->() const
	{
		return get();
	}

private:
	void swap(SharedPointer &a_another)
	{
		Base *const l_aux = m_aux;
		m_aux = a_another.m_aux;
		a_another.m_aux = l_aux;
	}

	Base *m_aux;
};

#endif //__SHAREDPOINTER_H
